package mysql

import (
	"fmt"
	"sync"

	"gitee.com/youkelike/ziam/zdb"
	"gitee.com/youkelike/ziam/zoptions/options"
	"gitee.com/youkelike/ziam/zorm/store"
	"gorm.io/gorm"
)

var (
	once sync.Once
)

type dataStore struct {
	db *gorm.DB
}

func (d *dataStore) Users() store.UserStore {
	return newUserStore(d)
}

func (d *dataStore) Secrets() store.SecretStore {
	return newSecrets(d)
}

func (d *dataStore) Policies() store.PolicyStore {
	return newPolicies(d)
}

func (ds *dataStore) PolicyAudits() store.PolicyAuditStore {
	return newPolicyAudits(ds)
}

func (d *dataStore) Close() error {
	db, err := d.db.DB()
	if err != nil {
		return err
	}

	return db.Close()
}

var factory store.Factory

// 这就是一个用途类似 NewDataStore 的方法，目的在于获取实现了数据库接口的实例
func GetMysqlFactoryOr(opts *options.MySQLOptions) (store.Factory, error) {
	if opts == nil && factory == nil {
		return nil, fmt.Errorf("failed to get mysql store fatory")
	}

	var err error
	var dbIns *gorm.DB
	once.Do(func() {
		options := &zdb.Options{
			Host:                  opts.Host,
			Username:              opts.Username,
			Password:              opts.Password,
			Database:              opts.Database,
			MaxIdleConnections:    opts.MaxIdleConnections,
			MaxOpenConnections:    opts.MaxOpenConnections,
			MaxConnectionLifeTime: opts.MaxConnectionLifeTime,
			LogLevel:              opts.LogLevel,
		}
		dbIns, err = zdb.New(options)

		factory = &dataStore{db: dbIns}

		store.SetClient(factory)
	})

	if factory == nil || err != nil {
		return nil, fmt.Errorf("failed to connect to mysql")
	}

	return factory, nil
}
